/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/**
 * 
 */
package cgl.narada.wsinfra.apps;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;

import org.apache.xmlbeans.XmlCursor;

import cgl.narada.wsinfra.deployment.Filter;
import cgl.narada.wsinfra.deployment.FilterPipeline;
import cgl.narada.wsinfra.deployment.FilterPipelineFactory;
import cgl.narada.wsinfra.deployment.NetworkSubstrate;
import cgl.narada.wsinfra.deployment.impl.NBNetworkSubstrate;
import cgl.narada.wsinfra.exception.DeploymentException;
import cgl.narada.wsinfra.exception.MessageFlowException;
import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.messaging.bootstrap.InitializationFactory;
import cgl.narada.wsinfra.messaging.bootstrap.Initializer;
import cgl.narada.wsinfra.messaging.entity.Publisher;
import cgl.narada.wsinfra.messaging.widget.Subscription;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.FromDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.util.SoapEnvelopeConversion;
import cgl.narada.wsinfra.wsa.WsaEnvelopeCreator;
import cgl.narada.wsinfra.wsa.WsaEprCreator;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;

/**
 * @author Shrideep Pallickara
 *
 */
public class MessagingPublisher {

	private WsaEprCreator wsaEprCreator;
	private WsaEnvelopeCreator wsaEnvelopeCreator;
	private SoapEnvelopeConversion soapEnvelopeConversion;
	
	private EndpointReferenceType publisherEPR, subscriptionMgrEPR;
	private Publisher publisher;
	private boolean isEventing = true;
	private int tracker = 0;
	
	private NetworkSubstrate networkSubstrate;
	private FilterPipelineFactory filterPipelineFactory;
   private FilterPipeline filterPipeline;
   private Filter publisherFilter, loggingFilter;
  
   private String moduleName = "MessagingPublisher: ";
	
	public MessagingPublisher(String publisherAddress, 
	                          String subscriptionManagerAddress,
	                          Properties networkProperties) 		
		throws DeploymentException {
		wsaEprCreator = WsaProcessingFactory.getWsaEprCreator();
		wsaEnvelopeCreator = WsaProcessingFactory.getWsaEnvelopeCreator();
		publisherEPR = wsaEprCreator.createEpr(publisherAddress);
		subscriptionMgrEPR = wsaEprCreator.createEpr(subscriptionManagerAddress);
		soapEnvelopeConversion = SoapEnvelopeConversion.getInstance();
		initializePublisher();
		initializeDeploymentEnvironment(networkProperties);
	}
	
	
	private void initializePublisher() throws DeploymentException {
		InitializationFactory initializationFactory =
			InitializationFactory.getInstance();
		Initializer initializer = initializationFactory.newInitializer(isEventing);
		publisher = initializer.createPublisher(publisherEPR, subscriptionMgrEPR);
	}
	
	
	private void initializeDeploymentEnvironment(Properties networkProperties)
		throws DeploymentException {
		
		filterPipelineFactory =  FilterPipelineFactory.getInstance();
	   filterPipeline = filterPipelineFactory.newFilterPipeline("MessagingPipeline");
	   
	   networkSubstrate = new NBNetworkSubstrate();
	   networkSubstrate.configureNetworking(networkProperties);
	    
	   networkSubstrate.registerPipeline(filterPipeline);
	   filterPipeline.registerNetworkSubstrate(networkSubstrate);
	   
	   publisherFilter = new PublisherFilter();
	   filterPipeline.addFilter(publisherFilter);
	   loggingFilter = new LoggingFilter();
	   filterPipeline.addFilter(loggingFilter);
	}
	
	
	
	public void listSubscriptionIdentifiers() {
		Enumeration e = publisher.getListOfSubscriptionIdentifiers();
		String report = "The list of registered subscription identifiers are: \n";
		while (e.hasMoreElements()) {
			String id = (String) e.nextElement();
			report += (id + "\n");
		}
		System.out.println(report);
	}
	
	public void printSubscriptionInfo(String subscriptionIdentifier) throws ProcessingException {
		Subscription subscription = publisher.getSubscription(subscriptionIdentifier);
		System.out.println(subscription);
	}
	
	
	 public SOAPMessage createSOAPMessage() {
	    EnvelopeDocument envelopeDocument = createEnvelopeDocument();
	    SOAPMessage soapMessage = null;
	    try {
	      soapMessage =  soapEnvelopeConversion.getSOAPMessage(envelopeDocument);
	    } catch (ProcessingException ex) {
	      String errorReport ="Problems converting to javax.xml.SOAPMessage\n"
		+ ex.toString();
	      System.out.println(errorReport);
	    }
	    
	    return soapMessage;
	  }
	
	private EnvelopeDocument createEnvelopeDocument() {
	    FromDocument from = FromDocument.Factory.newInstance();
	    from.setFrom(publisherEPR);
	    EnvelopeDocument envelopeDocument = 
	      wsaEnvelopeCreator.createSoapEnvelope(from);
	    
	    QName qname = new QName("http://www.naradabrokering.org",
				    "Application-Content");
	    XmlCursor bodyCursor = 
	      envelopeDocument.getEnvelope().getBody().newCursor();
	    tracker++;
	    

	    /** For sample XPath subscriptions */
	    String catalogUri = "http://www.naradabrokering.org/catalog";
	    bodyCursor.insertElement("catalog", catalogUri);
	    bodyCursor.toPrevToken();
	    bodyCursor.insertElement("cd", catalogUri);
	    bodyCursor.toPrevToken();
	    bodyCursor.insertElementWithText("price", catalogUri, "11.90");

	    /** For sample regular expression subscriptions. */
	    String value = "Tracker :" + tracker + "\n" +
	      "The quick brown fox jumps upon the lazy dog";
	    bodyCursor.toNextToken();
	    bodyCursor.insertElementWithText(qname, value);
	    bodyCursor.dispose();


	    bodyCursor = envelopeDocument.getEnvelope().getBody().newCursor();
	    String poUri = "http://openuri.org/easypo";
	    bodyCursor.insertElement("purchase-order", poUri);
	    bodyCursor.toPrevToken();
	    bodyCursor.insertElement("line-item", poUri);
	    bodyCursor.toPrevToken();
	    bodyCursor.insertElementWithText("price", poUri, "300");
	    bodyCursor.dispose();

	    String topicString = "/Literature/Shakespere";
	    try {
	   	 publisher.addTopicInfo(envelopeDocument, topicString);
	    } catch (ProcessingException pe) {
	   	 System.out.println("Problems adding topic info");
	    }
	    return envelopeDocument;
	  }
	
	public void sendSOAPMessage(SOAPMessage soapMessage) 
		throws DeploymentException, MessageFlowException, ProcessingException {
		
		filterPipeline.processMessageFromApplication(soapMessage);
	}
	
	public String createLinkTo(Properties props, String linkType) 
   	throws DeploymentException { 
		if (networkSubstrate == null) {
			System.out.println(moduleName + "The network substrate is null");
		}
		String linkId = 
			((NBNetworkSubstrate)networkSubstrate).createLinkTo(props, linkType);
		return linkId;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 3) {
			String errorReport = "Usage: java cgl.narada.wsinfra.apps.WseSourceEndpoint "
										+ "[hostname] [TCPServerPort] [WseSubManagerAddress]";
			System.out.println(errorReport);
			System.exit(0);
		}

		String hostname = args[0];
		String port = args[1];
		String wseSubManagerAddress = args[2];
		Properties props = new Properties();
		props.put("TCPServerPort", port);

		BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tok;
		String cmd;

		try {
			String sourceAddress = "tcp://" + hostname + ":" + port;
			MessagingPublisher endpoint = new MessagingPublisher(sourceAddress,
					wseSubManagerAddress, props);
			System.out.println("Listening to TCP communications on port [" + port
										+ "]. \n Type h for help on commands");
			while (true) {
				cmd = r.readLine();
				if (cmd == null) {
					System.out.println("Terminating program ....");
					break;
				}
				if (cmd.startsWith("h")) {
					System.out.println("Create Link           -> cr hostname portNum ");
					System.out.println("Send Notification     -> s");
					System.out.println("List subscription IDs -> l ");
					System.out.println("Print SubscriptionInfo-> p [subscriptionId] ");
				}

				if (cmd.startsWith("cr")) {
					tok = new StringTokenizer(cmd, " ");
					tok.nextToken(); /* skipping the token "cr" */
					Properties linkProps = new Properties();
					linkProps.put("hostname", tok.nextToken());
					linkProps.put("portnum", tok.nextToken());
					String _linkId = endpoint.createLinkTo(linkProps, "tcp");
					System.out.println("Created link with id => " + _linkId);
				}
				/** end create link */

				if (cmd.startsWith("s")) {
					SOAPMessage soapMessage = endpoint.createSOAPMessage();
					endpoint.sendSOAPMessage(soapMessage);
				}

				if (cmd.startsWith("l")) {
					endpoint.listSubscriptionIdentifiers();
				}
				
				if (cmd.startsWith("p")) {
					tok = new StringTokenizer(cmd, " ");
					if (tok.countTokens() != 2) {
						System.out.println("The correct usage of the Print Subscription Info is listed below");
						System.out.println("Print SubscriptionInfo-> p [subscriptionId] ");
						continue;
					}
					tok.nextToken(); /* skipping the token "p" */
					String subscriptionId = tok.nextToken();
					endpoint.printSubscriptionInfo(subscriptionId);
				}
				

			} /* end while(true) */

		} catch (Exception ioe) {
			ioe.printStackTrace();
		} /* end try-catch */
	}/*end main() */

	
}
